module.exports = app => {
    const express = require('express')
    const jwt = require('jsonwebtoken')
    const assert = require('http-assert')
    const AdminUser = require('../../models/AdminUser')

    const adminRouter = express.Router({
        mergeParams: true // 保留来自父路由器的 req.params 值。 如果父级和子级有冲突的参数名称，则子级的值优先
    })

    // 新建资源
    adminRouter.post('/', async(req, res) => {
        // 存入数据库
        const model = await req.Model.create(req.body)
        // 返回值
        res.send({
            code: 200,
            message: 'success',
            data: model
        })
    })

    // 资源列表
    adminRouter.get('/', async(req, res) => {
        const queryOptions = {}
        if(req.Model.modelName === 'Category') {
            queryOptions.populate = 'parent'
        }
        if(req.Model.modelName === 'Article') {
            queryOptions.populate = 'categories'
        }
        
        const model = await req.Model.find().setOptions(queryOptions).limit(100)  // populate 用于填充 parent 数据, 再模型中定义好引用的数据模型
        // const model = await req.Model.find().populate('parent').limit(10)  // populate 用于填充 parent 数据, 再模型中定义好引用的数据模型
        res.send(model)
    })

    // 资源详情
    adminRouter.get('/:id', async(req, res) => {
        const model = await req.Model.findById(req.params.id)
        res.send(model)
    })

    // 修改资源
    adminRouter.put('/:id', async(req, res) => {
        // 存入数据库
        const model = await req.Model.findByIdAndUpdate(req.params.id, req.body)
        // 返回值
        res.send({
            code: 200,
            message: 'success',
            data: model
        })
    })

    // 删除资源
    adminRouter.delete('/:id', async(req, res) => {
        await req.Model.findByIdAndDelete(req.params.id)
        res.send(true)
    })

    // 校验 token 中间件
    const authMiddleware = require('../../middleware/auth')

    // 获取资源中间件
    const resourceMiddleware = require('../../middleware/resource')

    app.use('/admin/api/curd/:resource', authMiddleware(), resourceMiddleware(), adminRouter)  // 将资源名称携程动态获取 :resource  curd 表示通用接口
    

    // 上传文件接口
    const multer = require('multer')
    const MAO = require('multer-aliyun-oss'); // https://www.npmjs.com/package/multer-aliyun-oss
    var upload = multer({ 
        // dest: __dirname + '/../../uploads' 
        storage: MAO({
            config: {
                region: 'oss-cn-hongkong',  // 地域
                accessKeyId: 'LTAI5tKE9aqqNmB513oiCUQT',
                accessKeySecret: 'SpmxfZWDaxKSYkYKnCtmmeCsTp2EzQ',
                bucket: 'node-vue-moba-oss'
            }
        })
    })
    app.use('/admin/api/upload',authMiddleware(), upload.single('file'), async(req, res) => {
        const file = req.file;
        // 改为阿里云 oss 之后，res里就有url信息
        // file.url = `http://test.why-fullstack.top/uploads/${file.filename}` //  需要 express.static()托管静态资源，才能访问
        // file.url = `http://localhost:3001/uploads/${file.filename}` //  需要 express.static()托管静态资源，才能访问
        res.send(file)
    })


    // 登录接口 admin 123456
    app.use('/admin/api/login', async(req, res) => {
        // 根据用户名找用户
        const { username, password } = req.body
        const userInfo = await AdminUser.findOne({username}).select('+password') // 数据表中默认不查密码，此时需要查找密码
        assert(userInfo, 422, '用户名错误')// 使用assert断言模块抛出错误，在错误处理中间统一处理
        // if(!userInfo) {
        //     return res.status(422).send({
        //         code: 422,
        //         message: '用户名错误'
        //     })
        // }

        // 校验密码
        const bcrypt = require('bcrypt')
        const isValid = bcrypt.compareSync(password, userInfo.password)
        assert(isValid, 422, '密码错误')  // 使用assert断言模块抛出错误，在错误处理中间统一处理
        // if(!isValid) {
        //     return res.status(422).send({  // 422 统一处理错误
        //         code: 422,
        //         message: '密码错误',
        //     })
        // }

        // 返回 token
        const token = jwt.sign({id: userInfo._id}, app.get('secret'))
        res.send({
            code: 200,
            token,
            message: 'success',
        })
    })

    
    // 错误处理中间件
    app.use(async (err, req, res, next) => {
        res.status(err.statusCode || 500).send({
            code: err.statusCode || 500,
            message: err.message
        })
    })
}